﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows.Controls.Primitives;
using System.Windows.Media;
using System.Windows;
using System.Windows.Controls;


namespace MercuryFE
{
    public enum ControlItemType
    {
        AD_Stick, Button, Dial, Joystick, Paddle, Pedal, Trackball
    }

    public enum ControlItemSubType
    {
        KB, JS, MS  // keyboard or joystick interface or Mouse
    }

    public enum ControlActionType
    {
        Button, Joystick, XY, Roll, Ball
    }

    public enum LabelPositionType
    {
        Above, Left, Below, Right, OnTop
    }
    /*
        AD_STICK
        BUTTON
        DIAL
        JOYSTICK
        LIGHTGUN
        PADDLE
        PEDAL
        TRACKBALL
     * */
    class ControlItem : Thumb, IComparable
    {
        
        public string ItemType { get; set; }
        //public Dictionary<string, string> Inputs;
        public List<ControlItemInput> Inputs;
        public SolidColorBrush Brush { get; set; }
        public bool IsSelected { get; set; }
        public int? SourceID { get; set; }
        public LabelPositionType LabelPosition { get; set; }
        public Point Position { get; set; }
        public ControlActionType ActionType { get; set; }
        public string AssignmentType { get; set; } // simple, ui, custom

        public string PlayerAssignment { get; set; }

        #region constants
        private Dictionary<string, string> availMamePlayers = new Dictionary<string, string>() { 
              { "P1", "Player 1" }
            , { "P2", "Player 2" }
            , { "P3", "Player 3" }
            , { "P4", "Player 4" } 
        };

        private Dictionary<string, string> availControlSubType = new Dictionary<string, string>() { 
              { "KB", "Keyboard interface" }
            , { "JS", "Joystick interface" }
        };

        private Dictionary<string, string> availMameRollDirections = new Dictionary<string, string>() { 
              { "", "Horizontal" }
            , { "V", "Vertical" }
        };

        private Dictionary<string, string> availMameJoysticks = new Dictionary<string, string>() {
              {"JOYSTICK"       ,"Joystick"}
            , {"JOYSTICKLEFT"   ,"Joystick Left"}
            , {"JOYSTICKRIGHT"  ,"Joystick Right"}
        };

        private Dictionary<string, string> availMameActions = new Dictionary<string, string>()
        {
             {"BUTTON"                , "BUTTON"  }
            ,{"COIN1"                 , "COIN1"  }
            ,{"COIN2"                 , "COIN2"  }
            ,{"COIN3"                 , "COIN3"  }
            ,{"COIN4"                 , "COIN4"   }
            ,{"SERVICE1"              , "SERVICE1"  }
            ,{"SERVICE2"              , "SERVICE2"  }
            ,{"SERVICE3"              , "SERVICE3"  }
            ,{"SERVICE4"              , "SERVICE4"  }
            ,{"START1"                , "START1"  }
            ,{"START2"                , "START2"  }
            ,{"START3"                , "START3"  }
            ,{"START4"                , "START4"  }
            ,{"TILT"                  , "TILT"  }
            ,{"UI_ADD_CHEAT"          , "UI_ADD_CHEAT"  }
            ,{"UI_CANCEL"             , "UI_CANCEL"  }
            ,{"UI_CONFIGURE"          , "UI_CONFIGURE"  }
            ,{"UI_DELETE_CHEAT"       , "UI_DELETE_CHEAT"  }
            ,{"UI_DOWN"               , "UI_DOWN"  }
            ,{"UI_EDIT_CHEAT"         , "UI_EDIT_CHEAT"  }
            ,{"UI_FRAMESKIP_DEC"      , "UI_FRAMESKIP_DEC"  }
            ,{"UI_FRAMESKIP_INC"      , "UI_FRAMESKIP_INC"  }
            ,{"UI_LEFT"               , "UI_LEFT"  }
            ,{"UI_LOAD_STATE"         , "UI_LOAD_STATE"  }
            ,{"UI_ON_SCREEN_DISPLAY"  , "UI_ON_SCREEN_DISPLAY"  }
            ,{"UI_PAN_DOWN"           , "UI_PAN_DOWN"  }
            ,{"UI_PAN_LEFT"           , "UI_PAN_LEFT"  }
            ,{"UI_PAN_RIGHT"          , "UI_PAN_RIGHT"  }
            ,{"UI_PAN_UP"             , "UI_PAN_UP"  }
            ,{"UI_PAUSE"              , "UI_PAUSE"  }
            ,{"UI_RESET_MACHINE"      , "UI_RESET_MACHINE"  }
            ,{"UI_RIGHT"              , "UI_RIGHT"  }
            ,{"UI_SAVE_CHEAT"         , "UI_SAVE_CHEAT"  }
            ,{"UI_SAVE_STATE"         , "UI_SAVE_STATE"  }
            ,{"UI_SELECT"             , "UI_SELECT"  }
            ,{"UI_SHOW_FPS"           , "UI_SHOW_FPS"  }
            ,{"UI_SHOW_GFX"           , "UI_SHOW_GFX"  }
            ,{"UI_SHOW_PROFILER"      , "UI_SHOW_PROFILER"  }
            ,{"UI_SNAPSHOT"           , "UI_SNAPSHOT"  }
            ,{"UI_THROTTLE"           , "UI_THROTTLE"  }
            ,{"UI_TOGGLE_CHEAT"       , "UI_TOGGLE_CHEAT"  }
            ,{"UI_TOGGLE_DEBUG"       , "UI_TOGGLE_DEBUG"  }
            ,{"UI_UP"                 , "UI_UP"  }
            ,{"UI_WATCH_VALUE"        , "UI_WATCH_VALUE"  }
        };

        Dictionary<string, string> availNums = new Dictionary<string, string>() { 
            {"1", "Button 1" },
            {"2","Button 2"  },
            {"3","Button 3"  },
            {"4","Button 4"  },
            {"5","Button 5"  },
            {"6","Button 6"  },
            {"7","Button 7"  },
            {"8","Button 8"  },
            {"9","Button 9"  },
            {"10","Button 10"  }
        };

        #endregion

        public ControlItem()  : base()        
        {
            Brush = new SolidColorBrush(Colors.Red);
            IsSelected = false;
            SourceID = null;
        }

        


        public ControlItem(ControlItemType itemType)
            : base()
        {
            SourceID = null;
            Inputs = new List<ControlItemInput>(); // new Dictionary<string, string>();
            LabelPosition = LabelPositionType.Above;
            switch (itemType)
            {
                case ControlItemType.AD_Stick:
                    this.Style =  Resources["myAD_Stick"] as Style;
                    this.ItemType = "AD_Stick";
                    this.ActionType = ControlActionType.XY;
                    break;
                case ControlItemType.Button:
                    this.Style = Application.Current.Resources["myButton"] as Style;
                    this.Inputs.Add(new ControlItemInput("ACTION", null));
                    this.ItemType = "Button";
                   // this.ItemSubType = "KB";
                    this.ActionType = ControlActionType.Button;
                    break;
                case ControlItemType.Dial:
                    this.Style = Application.Current.Resources["myDial"] as Style;
                    this.ItemType = "Dial";
                    this.ActionType = ControlActionType.Roll;
                    break;
                case ControlItemType.Joystick:
                    this.Style = Application.Current.Resources["myJoystick"] as Style;
                    this.Inputs.Add(new ControlItemInput("UP", null));
                    this.Inputs.Add(new ControlItemInput("LEFT", null));
                    this.Inputs.Add(new ControlItemInput("RIGHT", null));
                    this.Inputs.Add(new ControlItemInput("DOWN", null));
                    this.ItemType = "Joystick";
                    //this.ItemSubType = "KB";
                    this.ActionType = ControlActionType.Joystick;
                    break;
                case ControlItemType.Paddle:
                    this.Style = Application.Current.Resources["myPaddle"] as Style;
                    this.ItemType = "Paddle";
                    this.ActionType = ControlActionType.Roll;
                    break;
                case ControlItemType.Pedal:
                    this.Style = Application.Current.Resources["myPedal"] as Style;
                    this.Inputs.Add(new ControlItemInput("ACTION", null));
                    this.ItemType = "Pedal";
                    this.ActionType = ControlActionType.Button;
                    break;
                case ControlItemType.Trackball:
                    this.Style = Application.Current.Resources["myTrackball"] as Style;
                    this.ItemType = "Trackball";
                    this.ActionType = ControlActionType.Ball;
                    break;
            }


            Brush = new SolidColorBrush(Colors.Red);
            this.Background = Brush;
            this.ApplyTemplate();
        }

        public void PopulateSimpleAssignment(string playerString, string parameter)
        {

            // if joystick, parameter is JOYSTICK, JOYSTICKLEFT or JOYSTICKRIGHT
            // if button, it is the number

            switch ((ControlItemType)Enum.Parse(typeof(ControlItemType), this.ItemType))
            {
                case ControlItemType.AD_Stick:
                    break;
                case ControlItemType.Button:
                    this.Inputs[0].Assignment = playerString + "_BUTTON" + parameter;
                    break;
                case ControlItemType.Dial:
                    break;
                case ControlItemType.Joystick:
                    foreach (ControlItemInput input in this.Inputs)
                        input.Assignment = playerString + "_" + parameter + "_" + input.Name;

                    break;
                case ControlItemType.Paddle:
                    break;
                case ControlItemType.Pedal:
                    break;
                case ControlItemType.Trackball:
                    break;
            }
        }

        public void PopulateOtherAssignment(string inputName, string assignmentValue)
        {
            if (assignmentValue.Trim() == "")
                assignmentValue = null;

            foreach (ControlItemInput cii in this.Inputs)
            {
                if (cii.Name == inputName)
                {
                    cii.Assignment = assignmentValue;
                    break;
                }
            }
        }

        private ComboBox getComboBoxUI(string current)
        {
            ComboBox cmb = new ComboBox();

            cmb.Name = "UI";
            cmb.ItemsSource = availMameActions;
            cmb.DisplayMemberPath = "Value";

            if (current != null)
                cmb.SelectedItem = (from x in cmb.ItemsSource.Cast<KeyValuePair<string, string>>() where x.Key == current select x).SingleOrDefault();

            return cmb;
        }

        private ComboBox getComboBoxPlayers(string current)
        {
            ComboBox cmb = new ComboBox();

            cmb.Name = "Player";
            cmb.ItemsSource = availMamePlayers;
            cmb.DisplayMemberPath = "Value";

            if (current != null)
               cmb.SelectedItem = (from x in cmb.ItemsSource.Cast<KeyValuePair<string, string>>() where x.Key == current select x).SingleOrDefault();

            return cmb;
        }

        private ComboBox getComboBoxNumbers(string current)
        {
            ComboBox cmb = new ComboBox();

            cmb.Name = "Number";
            cmb.ItemsSource = availNums;
            cmb.DisplayMemberPath = "Value";

            if (current != null)
                cmb.SelectedItem = (from x in cmb.ItemsSource.Cast<KeyValuePair<string, string>>() where x.Key == current select x).SingleOrDefault();

            return cmb;
        }

        private ComboBox getComboBoxJoysticks(string current)
        {
            ComboBox cmb = new ComboBox();
            cmb.Name = "Joystick";
            cmb.ItemsSource = availMameJoysticks;
            cmb.DisplayMemberPath = "Value";

            if (current != null)
                cmb.SelectedItem = (from x in cmb.ItemsSource.Cast<KeyValuePair<string, string>>() where x.Key == current select x).SingleOrDefault();
            return cmb;
        }

        private ComboBox getComboBoxControlSubType(string current)
        {
            ComboBox cmb = new ComboBox();
            cmb.Name = "ControlSubType";
            cmb.ItemsSource = availControlSubType;
            cmb.DisplayMemberPath = "Value";

            if (current != null)
                cmb.SelectedItem = (from x in cmb.ItemsSource.Cast<KeyValuePair<string, string>>() where x.Key == current select x).SingleOrDefault();
            return cmb;
        }


        private bool IsSimpleAssignment(ref string playerString)
        {
            // check all the input assignments, and see if its conforms to 'simple assigment'
            bool isSimple = false;
            switch ((ControlItemType)Enum.Parse(typeof(ControlItemType), this.ItemType))
            {
                case ControlItemType.AD_Stick:
                    break;
                case ControlItemType.Button:
                    {
                        if (this.Inputs[0].Assignment == null)
                            isSimple = true;
                        else
                        {
                            string check = this.Inputs[0].Assignment.Substring(0, 3);
                            if (check[0] == 'P' && check[2] == '_')
                            {
                                isSimple = true;
                                playerString = check.Substring(0, 2);
                            }
                        }
                    }
                    break;
                case ControlItemType.Dial:
                    break;
                case ControlItemType.Joystick:
                    {
                        var check = (from x in this.Inputs 
                                     where x.Assignment != null 
                                     && x.Assignment.StartsWith("P")
                                              group x by x.Assignment.Substring(0, 3) into grp 
                                              select new {
                                                  grp.Key
                                                  , Count = grp.Count()
                                              }).ToList();

                        // never been set - use simple by defualt
                        if (check == null || check.Count == 0)
                            isSimple = true;
                        // otherwise check that all inputs have same prefix...
                        else if (check[0].Count == 4)
                        {
                            isSimple = true;
                            playerString = check[0].Key.Substring(0, 2);
                        }

                    }
                    break;
                case ControlItemType.Paddle:
                    break;
                case ControlItemType.Pedal:
                    break;
                case ControlItemType.Trackball:
                    break;
            }

            return isSimple;
        }

        private string getSimpleNumber()
        {
            // eg, P1_BUTTON3 - returns 3
            string number = null;
            switch ((ControlItemType)Enum.Parse(typeof(ControlItemType), this.ItemType))
            {
                 case ControlItemType.Button:
                    {
                        if (this.Inputs[0].Assignment != null)
                        {
                            string[] arrTemp = this.Inputs[0].Assignment.Split('_');
                            number = arrTemp[1].Substring(6);
                        }
                    }
                    break;
            }
            return number;
        }

        private string getSimpleJoystick()
        {
            string joystick = null;
            switch ((ControlItemType)Enum.Parse(typeof(ControlItemType), this.ItemType))
            {
                case ControlItemType.Joystick:
                    {
                        if (this.Inputs[0].Assignment != null)
                        {
                            string[] arrTemp = this.Inputs[0].Assignment.Split('_');
                            joystick = arrTemp[1];
                        }
                    }
                    break;
            }
            return joystick;
        }

        public List<UIElement> GetAssignmentSelectors()
        {


            List<UIElement> elements = new List<UIElement>();
            string playerString = null;
            bool isSimple = IsSimpleAssignment(ref playerString);

            if (this.AssignmentType == "simple") //IsSimpleMode)
            {
                switch ((ControlItemType)Enum.Parse(typeof(ControlItemType), this.ItemType))
                {
                    case ControlItemType.AD_Stick:
                        break;
                    case ControlItemType.Button:
                        {
                            // just need to show player selector and number
                            elements.Add(getComboBoxPlayers(playerString));
                            elements.Add(getComboBoxNumbers(getSimpleNumber()));
                        }
                        break;
                    case ControlItemType.Dial:
                        break;
                    case ControlItemType.Joystick:
                        {
                            // just need to show player selector and joystick selector
                            elements.Add(getComboBoxPlayers(playerString));
                            elements.Add(getComboBoxJoysticks(getSimpleJoystick()));
                        }
                        break;
                    case ControlItemType.Paddle:
                        break;
                    case ControlItemType.Pedal:
                        break;
                    case ControlItemType.Trackball:
                        break;
                }
            }
            else if (this.AssignmentType == "custom")
            {
                // add text boxes for all the inputs.
                foreach (ControlItemInput input in this.Inputs)
                {
                    StackPanel sp = new StackPanel()
                    {
                        Orientation = Orientation.Horizontal
                    };

                    Label l = new Label() { Content = input.Name, Name = "lbl" + input.Name };
                    sp.Children.Add(l);

                    TextBox tb = new TextBox() { Width = 60, Name = "tb" + input.Name };
                    sp.Children.Add(tb);

                    elements.Add(sp);
                }
            }
            else if (this.AssignmentType == "ui")
            {
                // add drop downs for all the inputs.
                foreach (ControlItemInput input in this.Inputs)
                {
                    StackPanel sp = new StackPanel()
                    {
                        Orientation = Orientation.Horizontal
                    };

                    Label l = new Label() { Content = input.Name, Name = "lbl" + input.Name };
                    sp.Children.Add(l);

                    ComboBox cmb = getComboBoxUI(input.Assignment);
                    cmb.Name = "cmb" + input.Name;
                    sp.Children.Add(cmb);

                    elements.Add(sp);
                }
            }

            return elements;
        }

        int IComparable.CompareTo(object obj)
        {
            ControlItem Compare = (ControlItem)obj;

            if (this.Position.X == Compare.Position.X)
            {
                return this.Position.Y.CompareTo(Compare.Position.Y);
            }
            else
                return this.Position.X.CompareTo(Compare.Position.X);

        }

    }

    class ControlItemInput
    {
        public string Name { get; set; }
        public string KeyCode { get; set; }
        public string Assignment { get; set; }
        public string AssignmentType { get; set; }
        public string AssignmentSubType { get; set; }
        public int? SourceID { get; set; }

        public ControlItemInput(string name, string keyCode)
        {
            Name = name;
            KeyCode = keyCode;
            SourceID = null;
        }

        public ControlItemInput(string name, string keyCode, int sourceId)
        {
            Name = name;
            KeyCode = keyCode;
            SourceID = sourceId;
        }

    }
}
